package org.alvin.code.jdbc.ormx.utils;

import org.alvin.code.jdbc.JDBCBaseDao;
import org.alvin.code.jdbc.ormx.annocations.MinCol;
import org.alvin.code.jdbc.ormx.annocations.MinId;
import org.alvin.code.jdbc.ormx.annocations.MinTable;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * jdbc 扩展
 */
public class JDBCBaseDaoX extends JDBCBaseDao {
    /**
     * 单个保存
     *
     * @param o
     * @return
     * @throws Exception
     */
    public int save(Object o) throws Exception {
        String tableName = o.getClass().getAnnotation(MinTable.class).value();
        List<String> fields = new ArrayList<>();
        List<Object> fieldDatas = new ArrayList<>();
        String idName = null;
        Field idField = null;
        for (Field f : o.getClass().getDeclaredFields()) {
            boolean accessabled = f.isAccessible();
            try {
                f.setAccessible(true);
                MinId id = f.getAnnotation(MinId.class);
                if (id != null) {
                    idName = id.value();
                    idField = f;
                }
                MinCol col = f.getAnnotation(MinCol.class);
                if (col != null) {
                    fields.add(col.value());
                    fieldDatas.add(f.get(o));
                }
            }finally {
                f.setAccessible(accessabled);
            }
        }
        String fieldsParams = fields.stream().collect(Collectors.joining(","));
        String fieldsValues = fields.stream().map(item -> "?").collect(Collectors.joining(","));
        String sql = "insert into " + tableName + " (" + fieldsParams + ") values (" + fieldsValues + ")";
        System.out.println(sql);
        System.out.println(fieldDatas);
        Map<String, Object> keyMap = new HashMap<>();
        int res = super.saveReturnPK(sql, fieldDatas.toArray(), keyMap, idName);
        boolean accessable = idField.isAccessible();
        try {
            idField.setAccessible(true);
            idField.set(o, keyMap.get(idName));
        } finally {
            idField.setAccessible(accessable);
        }
        return res;
    }

    /**
     * 批量保存
     *
     * @param list
     * @return
     */
    public int[] batchSave(List<Object> list) throws Exception {
        if (list.isEmpty()) {
            return new int[0];
        }
        Object o = list.get(0);
        String tableName = o.getClass().getAnnotation(MinTable.class).value();
        List<String> fields = new ArrayList<>();
        List<Object[]> fieldDatas = new ArrayList<>();
        String idName = null;
        Field idField = null;

        for (Object oi : list) {
            List<Object> objDatas = new ArrayList<>();
            for (Field f : oi.getClass().getDeclaredFields()) {
                boolean accessabled = f.isAccessible();
                try {
                    f.setAccessible(true);
                    MinId id = f.getAnnotation(MinId.class);
                    if (id != null) {
                        idName = id.value();
                        idField = f;
                    }
                    MinCol col = f.getAnnotation(MinCol.class);
                    if (col != null) {
                        fields.add(col.value());
                        objDatas.add(f.get(oi));
                    }
                } finally {
                    f.setAccessible(accessabled);
                }
            }
            fieldDatas.add(objDatas.toArray());
        }
        String fieldsParams = fields.stream().collect(Collectors.joining(","));
        String fieldsValues = fields.stream().map(item -> "?").collect(Collectors.joining(","));
        String sql = "insert into " + tableName + " (" + fieldsParams + ") values (" + fieldsValues + ")";
        System.out.println(sql);
        System.out.println(fieldDatas);
        List<Map<String, Object>> keyMaps = new ArrayList<>();
        int[] res = super.saveBatchReturnPk(sql, fieldDatas, keyMaps, idName);
        boolean accessable = idField.isAccessible();
        try {
            idField.setAccessible(true);
            for (int i = 0; i < list.size(); i++) {
                idField.set(list.get(i), keyMaps.get(i).get(idName));
            }
        } finally {
            idField.setAccessible(accessable);
        }
        return res;
    }

    /**
     * 修改
     *
     * @param o
     * @return
     */
    public int update(Object o) throws Exception {
        String tableName = o.getClass().getAnnotation(MinTable.class).value();
        List<String> fields = new ArrayList<>();
        List<Object> fieldDatas = new ArrayList<>();
        String idName = null;
        Field idField = null;
        for (Field f : o.getClass().getDeclaredFields()) {
            boolean accessable = f.isAccessible();
            try {
                f.setAccessible(true);
                MinId id = f.getAnnotation(MinId.class);
                if (id != null) {
                    idName = id.value();
                    idField = f;
                }
                MinCol col = f.getAnnotation(MinCol.class);
                if (col != null && f.get(o) != null) {
                    fields.add(col.value());
                    fieldDatas.add(f.get(o));
                }
            } finally {
                f.setAccessible(accessable);
            }
        }
        String fieldsParams = fields.stream().map(item -> item.concat("=?")).collect(Collectors.joining(","));
        String sql = "update " + tableName + " set " + fieldsParams + " where " + idName + "=?";
        boolean accessable = idField.isAccessible();
        try {
            idField.setAccessible(true);
            fieldDatas.add(idField.get(o));
        } finally {
            idField.setAccessible(accessable);
        }
        return super.update(sql, fieldDatas.toArray());
    }

    /**
     * 批量修改
     *
     * @param list
     * @return
     */
    public int[] update(List<Object> list) throws Exception {
        if (list.isEmpty()) {
            return new int[0];
        }
        Object o = list.get(0);
        String tableName = o.getClass().getAnnotation(MinTable.class).value();
        List<String> fields = new ArrayList<>();
        List<Object[]> fieldDatas = new ArrayList<>();
        String idName = null;
        Field idField = null;
        for (Object oi : list) {
            List<Object> fieldParams = new ArrayList<>();
            for (Field f : oi.getClass().getDeclaredFields()) {
                boolean accessable = f.isAccessible();
                try {
                    f.setAccessible(true);
                    MinId id = f.getAnnotation(MinId.class);
                    if (id != null) {
                        idName = id.value();
                        idField = f;
                    }
                    MinCol col = f.getAnnotation(MinCol.class);
                    if (col != null) {
                        fields.add(col.value());
                        fieldParams.add(f.get(oi));
                    }
                }finally {
                    f.setAccessible(accessable);
                }
            }
            boolean accessale = idField.isAccessible();
            try {
                idField.setAccessible(true);
                fieldParams.add(idField.get(oi));
            }finally {
                idField.setAccessible(accessale);
            }
            fieldDatas.add(fieldParams.toArray());
        }
        String fieldsParams = fields.stream().map(item -> item.concat("=?")).collect(Collectors.joining(","));
        String sql = "update " + tableName + " set " + fieldsParams + " where " + idName + "=?";
        return super.update(sql, fieldDatas);
    }
}
